/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.repair.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.config.ProjectApiConfiguration;
import org.springblade.common.utils.AsyncHttpUtil;
import org.springblade.common.utils.RobotUtil;
import org.springblade.common.utils.mq.AlarmSend;
import org.springblade.common.utils.mq.MqMessageService;
import org.springblade.common.utils.mq.NormalSend;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseEntity;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springblade.modules.notice.core.event.NoticeEvent;
import org.springblade.modules.notice.dto.NoticeTaskParam;
import org.springblade.modules.notice.enums.BusinessType;
import org.springblade.modules.notice.enums.TriggerConditionEnum;
import org.springblade.modules.notice.enums.TriggerNodeEnum;
import org.springblade.modules.repair.dto.PlanCheckStatisticsQueryDTO;
import org.springblade.modules.repair.dto.PlanLogDTO;
import org.springblade.modules.repair.dto.PlanUserSignCountDTO;
import org.springblade.modules.repair.dto.RobotContentDTO;
import org.springblade.modules.repair.entity.*;
import org.springblade.modules.repair.enums.*;
import org.springblade.modules.repair.mapper.MaintainSignMapper;
import org.springblade.modules.repair.service.*;
import org.springblade.modules.repair.utils.DateUtils;
import org.springblade.modules.repair.vo.*;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 维保签到明细 服务实现类
 *
 * @author BladeX
 * @since 2021-05-21
 */
@Service
@Slf4j
public class MaintainSignServiceImpl extends BaseServiceImpl<MaintainSignMapper, MaintainSign> implements IMaintainSignService {

	@Resource
	private IMaintainCheckHistoryService checkHistoryService;
	@Resource
	private IMaintainMalfunctionLogService malfunctionLogService;
	@Resource
	private IMaintainPlanContentService planContentService;
	@Lazy
	@Resource
	private IUserService userService;
	@Resource
	private IMaintainPlanContentUserService maintainPlanContentUserService;
	@Autowired
	private IMaintainPlanContentExtService maintainPlanContentExtService;
	@Autowired
	private AlarmSend alarmSend;
	@Autowired
	private NormalSend normalSend;

	@Autowired
	private ElevatorDetailService elevatorDetailService;
	@Autowired
	@Lazy
	private IMaintainMalfunctionWorkService malfunctionWorkService;

	@Autowired
	@Lazy
	private IMaintainPlanContentService maintainPlanContentService;

	@Lazy
	@Resource
	private IElevatorService elevatorService;

	@Autowired
	private ElevatorDriveModeService elevatorDriveModeService;
	@Autowired
	private RobotUtil robotUtil;
	@Autowired
	private AsyncHttpUtil asyncHttpUtil;
	@Autowired
	private ProjectApiConfiguration projectApiConfiguration;
	@Autowired
	private MqMessageService mqMessageService;
	@Autowired
	private IMaintainPlanTemplateService maintainPlanTemplateService;
	@Autowired
	private IMaintainPartsTemplateAttributeService maintainPartsTemplateAttributeService;
	@Autowired
	private IMaintainPlanTemplatePartsAttributeService maintainPlanTemplatePartsAttributeService;
	@Resource
	private ApplicationEventPublisher eventPublisher;
	@Lazy
	@Autowired
	private MaintainAbarbeitungService abarbeitungService;

	@Override
	@Transactional(rollbackFor = Exception.class)
	public synchronized Boolean sign(MaintainSign maintainSign) {
		Long planIdFirst = maintainSign.getPlanId();
		MaintainPlanContent planContent = planContentService.getById(planIdFirst);
		if (DateUtil.compare(planContent.getPlanDate(), new Date(), "yyyy-MM-dd") > 0) {
			throw new ServiceException("任务状态已更新，请刷新页面");
		}

		//计算维修预警状态
		Integer wxArriveStatus = null;
		MaintainPlanContentUser planContentUser = maintainPlanContentUserService.getOne(Wrappers.<MaintainPlanContentUser>lambdaQuery().eq(MaintainPlanContentUser::getPlanId, planIdFirst).eq(MaintainPlanContentUser::getUserId, AuthUtil.getUserId()));
		if (planContentUser == null) {
			throw new ServiceException("任务状态已更新，请刷新页面");
		}
		if (planContentUser.getPlanArriveDate() != null && planContent.getWxTypeStatus() == null) {
			if (System.currentTimeMillis() <= planContentUser.getPlanArriveDate().getTime()) {
				wxArriveStatus = WxArriveStatusEnums.ARRIVE_ON_TIME.getId();
			} else {
				wxArriveStatus = WxArriveStatusEnums.DIS_ARRIVE_ON_TIME.getId();
			}
		}
		final Long elevatorId = planContent.getElevatorId();
		log.info("获取的电梯id================" + planContent.getElevatorId());
		// 2024-10-17 新增 工单_工作项_模板_配件维保属性关联数据保存
		List<MaintainPlanTemplate> relationTemplateList = maintainPlanTemplateService.list(new LambdaQueryWrapper<MaintainPlanTemplate>()
			.eq(MaintainPlanTemplate::getPlanId, planIdFirst)
			.eq(BaseEntity::getIsDeleted, 0)
		);
		if (Func.isNotEmpty(relationTemplateList)) {
			relationTemplateList.forEach(r -> {
				// 无论是否已存在，都插入
				Long currentTemplateId = r.getTemplateId();
				List<MaintainPartsTemplateAttributeDetailVO> maintainPartsTemplateAttributeDetailVOS = maintainPartsTemplateAttributeService.listByTemplateId(currentTemplateId);
				List<MaintainPlanTemplatePartsAttribute> targetList = new ArrayList<>();
				if (!Func.isEmpty(maintainPartsTemplateAttributeDetailVOS)) {
					maintainPartsTemplateAttributeDetailVOS.forEach(m -> {
						MaintainPlanTemplatePartsAttribute target = new MaintainPlanTemplatePartsAttribute();
						target.setAttributeId(m.getAttributeId());
						target.setAttributeName(m.getAttributeName());
						target.setTemplateId(currentTemplateId);
						target.setPartId(m.getPartId());
						target.setPartName(m.getPartName());
						target.setPlanId(planIdFirst);
						targetList.add(target);
					});
					if (Func.isNotEmpty(targetList)) {
						maintainPlanTemplatePartsAttributeService.saveBatch(targetList);
					}
				}
			});
		}
		List<Long> userPlanIds = planContentService.listUserPlan(planContent.getTypeStatus(), maintainSign.getPlanId(), maintainSign.getUserId());
		if (ObjectUtil.isNotEmpty(userPlanIds) && userPlanIds.size() >= 1) {
			int count = super.count(Wrappers.<MaintainSign>lambdaQuery()
				.in(MaintainSign::getPlanId, userPlanIds)
				.eq(MaintainSign::getUserId, maintainSign.getUserId())
				.isNull(MaintainSign::getSignOutTime));
			if (count > 0) {
				throw new ServiceException("有未签退的" + MaintainPlanContentEnum.getName(planContent.getTypeStatus()) + "任务，请先签退，再开始新的任务");
			}
		}

		User user = userService.getById(maintainSign.getUserId());
		maintainSign.setTenantId(AuthUtil.getTenantId());
		long currentTimeMillis = System.currentTimeMillis();
		Date signDate = new Date(currentTimeMillis);
		maintainSign.setSignTime(signDate);
		int typeStatus = planContent.getTypeStatus();

		ElevatorDetailVO elevatorDetailVO = elevatorService.selectElevatorDetail(planContent.getElevatorId());
		List<MaintainPlanContentUser> planContentUsers = maintainPlanContentUserService.listUserByPlan(maintainSign.getPlanId());
		// 检查签到人是否是任务执行人
		if (planContentUsers.stream().noneMatch(t -> Func.equalsSafe(t.getUserId(), AuthUtil.getUserId()))) {
			throw new ServiceException("任务状态已更新，请刷新页面");
		}
		List<String> userName = planContentUsers.stream().map(MaintainPlanContentUser::getUserName).collect(Collectors.toList());

		if (MaintainPlanContentEnum.MAINTAIN_BY.getId() == planContent.getTypeStatus()) {
			if (TaskStatusEnum.BY_FINISH.getStatus() == planContent.getStatus() || TaskStatusEnum.BY_SIGN.getStatus() == planContent.getStatus()) {
				throw new ServiceException("任务状态已更新，请刷新页面");
			} else if (TaskStatusEnum.BY_DISABLE.getStatus() == planContent.getStatus()) {
				// 插入签到记录
				super.save(maintainSign);

				// 生成工作项历史记录
				checkHistoryService.addHistory(maintainSign.getPlanId());

				// 修改任务状态
				planContent.setStatus(TaskStatusEnum.BY_PROCESSED.getStatus());
				planContentService.updateById(planContent);

				// 跟新任务扩展表任务开始时间
				MaintainPlanContentExt maintainPlanContentExt = maintainPlanContentExtService.getOne(Wrappers.<MaintainPlanContentExt>lambdaQuery().eq(MaintainPlanContentExt::getPlanId, maintainSign.getPlanId()));
				maintainPlanContentExt.setPlanBeginTime(signDate);
				maintainPlanContentExtService.updateById(maintainPlanContentExt);

				// 【保养开始】群消息推送
				RobotContentDTO robotContentDTO = new RobotContentDTO();
				robotContentDTO.setMaintainType(MaintainPlanContentEnum.MAINTAIN_BY.getId());
				robotContentDTO.setMaintainSubTypeDesc("【开始保养通知】");
				StringBuilder locationDesc = new StringBuilder();
				locationDesc.append(elevatorDetailVO.getBuildingName()).append("-").append(elevatorDetailVO.getElevatorAddress());
				robotContentDTO.setLocationDesc(locationDesc.toString());
				robotContentDTO.setMaintainStatusDesc(TaskStatusEnum.getTaskName(MaintainPlanContentEnum.MAINTAIN_BY.getId(), planContent.getStatus()));
				robotContentDTO.setElevatorStatusDesc(ElevatorStatusEnum.getName(maintainSign.getIsStop()));
				List<MaintainPlanContentUser> planUsers = maintainPlanContentUserService.listUserByPlan(planContent.getId());
				robotContentDTO.setMaintainPersonDesc(planUsers.stream().map(t -> t.getUserName()).collect(Collectors.joining(",")));
				robotContentDTO.setMaintainPersonImgDesc(planUsers.stream().map(t -> t.getAvatar()).collect(Collectors.joining(",")));
				robotContentDTO.setMaintainImgUrl(StringUtil.isNotBlank(maintainSign.getSignImage()) ? maintainSign.getSignImage() : "https://erised.oss-cn-shenzhen.aliyuncs.com/img/202308251732973.png");
				robotContentDTO.setMaintainTimeDesc(DateUtils.newChineseDate(maintainSign.getFinishDate()));
				robotUtil.sendRobotMessage(RequestContextHolder.getRequestAttributes(), planContent.getElevatorId(), planContent.getId(), robotContentDTO);
			} else {
				// 未签退的记录
				int notSignOutCount = count(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, planContent.getId()).isNull(MaintainSign::getSignOutStatus));
				// 插入签到记录
				super.save(maintainSign);
				if (notSignOutCount == 0) {
					// 【保养到场】群消息推送
					RobotContentDTO robotContentDTO = new RobotContentDTO();
					robotContentDTO.setMaintainType(MaintainPlanContentEnum.MAINTAIN_BY.getId());
					robotContentDTO.setMaintainSubTypeDesc("【保养到场通知】");
					StringBuilder locationDesc = new StringBuilder();
					locationDesc.append(elevatorDetailVO.getBuildingName()).append("-").append(elevatorDetailVO.getElevatorAddress());
					robotContentDTO.setLocationDesc(locationDesc.toString());
					robotContentDTO.setMaintainStatusDesc(TaskStatusEnum.getTaskName(MaintainPlanContentEnum.MAINTAIN_BY.getId(), planContent.getStatus()));
					robotContentDTO.setElevatorStatusDesc(ElevatorStatusEnum.getName(maintainSign.getIsStop()));
					List<MaintainPlanContentUser> planUsers = maintainPlanContentUserService.listUserByPlan(planContent.getId());
					robotContentDTO.setMaintainPersonDesc(planUsers.stream().map(t -> t.getUserName()).collect(Collectors.joining(",")));
					robotContentDTO.setMaintainPersonImgDesc(planUsers.stream().map(t -> t.getAvatar()).collect(Collectors.joining(",")));
					robotContentDTO.setMaintainImgUrl(StringUtil.isNotBlank(maintainSign.getSignImage()) ? maintainSign.getSignImage() : "https://erised.oss-cn-shenzhen.aliyuncs.com/img/202308251731106.png");
					robotContentDTO.setMaintainTimeDesc(DateUtils.newChineseDate(maintainSign.getFinishDate()));
					robotContentDTO.setNotPushCard(true);
					robotUtil.sendRobotMessage(RequestContextHolder.getRequestAttributes(), planContent.getElevatorId(), planContent.getId(), robotContentDTO);
				}
			}
		} else if (MaintainPlanContentEnum.MAINTAIN_WX.getId() == planContent.getTypeStatus()) {
			List<MaintainMalfunctionWork> malfunctionWork = malfunctionWorkService.list(Wrappers.<MaintainMalfunctionWork>lambdaQuery().eq(MaintainMalfunctionWork::getPlanId, planContent.getId()).orderByAsc(MaintainMalfunctionWork::getId));
			// 机器人消息内容
			RobotContentDTO robotContentDTO = new RobotContentDTO();
			robotContentDTO.setMaintainType(MaintainPlanContentEnum.MAINTAIN_WX.getId());
			StringBuilder locationDesc = new StringBuilder();
			locationDesc.append(elevatorDetailVO.getBuildingName()).append("-").append(elevatorDetailVO.getElevatorAddress());
			robotContentDTO.setLocationDesc(locationDesc.toString());
			robotContentDTO.setMaintainStatusDesc(TaskStatusEnum.WX_UNDER_WAY.getName());
			robotContentDTO.setElevatorStatusDesc(ElevatorStatusEnum.getName(maintainSign.getIsStop()));
			robotContentDTO.setMaintainPersonDesc(String.join(",", userName));
			robotContentDTO.setMaintainTimeDesc(DateUtils.chineseDate(maintainSign.getFinishDate()));
			robotContentDTO.setMalfunctionDesc(malfunctionWork.get(0).getMfDesc());

			if (TaskStatusEnum.WX_SIGN_FINISH.getStatus() == planContent.getStatus() || TaskStatusEnum.WX_CHECK_PASS_CLOSED.getStatus() == planContent.getStatus()) {
				throw new ServiceException("任务状态已更新，请刷新页面");
			} else if (TaskStatusEnum.WX_TO_START.getStatus() == planContent.getStatus()) {
				// 插入签到记录
				super.save(maintainSign);

				// 修改任务状态
				planContent.setStatus(TaskStatusEnum.WX_UNDER_WAY.getStatus());
				planContentService.updateById(planContent);

				// 跟新任务扩展表任务开始时间
				MaintainPlanContentExt maintainPlanContentExt = maintainPlanContentExtService.getOne(Wrappers.<MaintainPlanContentExt>lambdaQuery().eq(MaintainPlanContentExt::getPlanId, maintainSign.getPlanId()));
				maintainPlanContentExt.setArriveTime(signDate);
				maintainPlanContentExt.setArriveDuration(signDate.getTime() - planContent.getCreateTime().getTime());
				maintainPlanContentExt.setPlanBeginTime(signDate);
				if (maintainPlanContentExt.getWxArriveStatus() == null) {
					maintainPlanContentExt.setWxArriveStatus(wxArriveStatus);
				} else {
					if (maintainPlanContentExt.getWxArriveStatus() == 3) {
						maintainPlanContentExt.setWxArriveStatus(2);
					}
				}
				maintainPlanContentExtService.updateById(maintainPlanContentExt);

				// 维修开始发送消息
				robotContentDTO.setMaintainImgUrl(StringUtil.isNotBlank(maintainSign.getSignImage()) ? maintainSign.getSignImage() : "https://erised.oss-cn-shenzhen.aliyuncs.com/img/202308251732973.png");
				robotContentDTO.setMaintainSubTypeDesc("【开始维修通知】");
				robotUtil.sendRobotMessage(RequestContextHolder.getRequestAttributes(), planContent.getElevatorId(), planContent.getId(), robotContentDTO);
			} else {
				// 插入签到记录
				super.save(maintainSign);

				// 维修进场发送消息
				int planSignCount = super.count(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, maintainSign.getPlanId()).isNull(MaintainSign::getSignOutTime));
				if (planSignCount == 1) {
					// 当前工单
					robotContentDTO.setMaintainSubTypeDesc("【维修到场通知】");
					robotContentDTO.setMaintainImgUrl(StringUtil.isNotBlank(maintainSign.getSignImage()) ? maintainSign.getSignImage() : "https://erised.oss-cn-shenzhen.aliyuncs.com/img/202308251731106.png");
					robotContentDTO.setNotPushCard(true);
					robotUtil.sendRobotMessage(RequestContextHolder.getRequestAttributes(), planContent.getElevatorId(), planContent.getId(), robotContentDTO);
				}
			}

		} else if (MaintainPlanContentEnum.MAINTAIN_PARTS.getId() == planContent.getTypeStatus()) {
			if (TaskStatusEnum.PARTS_FINISH.getStatus() == planContent.getStatus()) {
				throw new ServiceException("任务状态已更新，请刷新页面");
			} else if (TaskStatusEnum.PARTS_TO_START.getStatus() == planContent.getStatus()) {
				// 插入签到记录
				super.save(maintainSign);

				// 修改任务状态
				planContent.setStatus(TaskStatusEnum.PARTS_CHANGE.getStatus());
				planContentService.updateById(planContent);

				// 跟新任务扩展表任务开始时间
				MaintainPlanContentExt maintainPlanContentExt = maintainPlanContentExtService.getOne(Wrappers.<MaintainPlanContentExt>lambdaQuery().eq(MaintainPlanContentExt::getPlanId, maintainSign.getPlanId()));
				maintainPlanContentExt.setPlanBeginTime(signDate);
				maintainPlanContentExtService.updateById(maintainPlanContentExt);

			} else {
				// 插入签到记录
				super.save(maintainSign);
			}
		} else if (MaintainPlanContentEnum.MAINTAIN_AFFAIR.getId() == planContent.getTypeStatus()) {
			if (TaskStatusEnum.SW_SIGN_FINISH.getStatus() == planContent.getStatus() || TaskStatusEnum.SW_CLOSED.getStatus() == planContent.getStatus()) {
				throw new ServiceException("任务状态已更新，请刷新页面");
			} else if (TaskStatusEnum.SW_TO_START.getStatus() == planContent.getStatus()) {
				// 插入签到记录
				super.save(maintainSign);

				// 修改任务状态
				planContent.setStatus(TaskStatusEnum.SW_UNDER_WAY.getStatus());
				planContentService.updateById(planContent);

				// 跟新任务扩展表任务开始时间
				MaintainPlanContentExt maintainPlanContentExt = maintainPlanContentExtService.getOne(Wrappers.<MaintainPlanContentExt>lambdaQuery().eq(MaintainPlanContentExt::getPlanId, maintainSign.getPlanId()));
				maintainPlanContentExt.setPlanBeginTime(signDate);
				maintainPlanContentExtService.updateById(maintainPlanContentExt);
			} else {
				// 插入签到记录
				super.save(maintainSign);
			}
		} else if (MaintainPlanContentEnum.MAINTAIN_CHECK.getId() == planContent.getTypeStatus()) {
			if (TaskStatusEnum.ZJ_SIGN_FINISH.getStatus() == planContent.getStatus() || TaskStatusEnum.ZJ_CLOSED.getStatus() == planContent.getStatus()) {
				throw new ServiceException("任务状态已更新，请刷新页面");
			} else if (TaskStatusEnum.ZJ_TO_START.getStatus() == planContent.getStatus()) {
				// 插入签到记录
				super.save(maintainSign);

				// 修改任务状态
				planContent.setStatus(TaskStatusEnum.ZJ_UNDER_WAY.getStatus());
				planContentService.updateById(planContent);

				// 跟新任务扩展表任务开始时间
				MaintainPlanContentExt maintainPlanContentExt = maintainPlanContentExtService.getOne(Wrappers.<MaintainPlanContentExt>lambdaQuery().eq(MaintainPlanContentExt::getPlanId, maintainSign.getPlanId()));
				maintainPlanContentExt.setPlanBeginTime(signDate);
				maintainPlanContentExtService.updateById(maintainPlanContentExt);
			} else {
				// 插入签到记录
				super.save(maintainSign);
			}
		} else if (MaintainPlanContentEnum.ABARBEITUNG.getId() == planContent.getTypeStatus()) {
			if (TaskStatusEnum.ZG_TO_START.getStatus() == planContent.getStatus()) {
				// 插入签到记录
				super.save(maintainSign);

				// 生成工作项历史记录
				abarbeitungService.addHistory(maintainSign.getPlanId());

				// 修改任务状态
				planContent.setStatus(TaskStatusEnum.ZG_UNDER_WAY.getStatus());
				planContentService.updateById(planContent);

				// 跟新任务扩展表任务开始时间
				MaintainPlanContentExt maintainPlanContentExt = maintainPlanContentExtService.getOne(Wrappers.<MaintainPlanContentExt>lambdaQuery().eq(MaintainPlanContentExt::getPlanId, maintainSign.getPlanId()));
				maintainPlanContentExt.setPlanBeginTime(signDate);
				maintainPlanContentExtService.updateById(maintainPlanContentExt);
			} else {
				// 插入签到记录
				super.save(maintainSign);
			}
		}

		// 保养/维修 更新预计完成时间
		if (ObjectUtil.isNotEmpty(maintainSign.getFinishDate())) {
			MaintainPlanContent entity = new MaintainPlanContent();
			entity.setId(planContent.getId());
			entity.setFinishDate(maintainSign.getFinishDate());
			planContentService.updateById(entity);

			long deliverTime = maintainSign.getFinishDate().getTime() - 5 * 60000;
			if (planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_WX.getId())) {
				// 推送通知-已到预计维修结束时间
				eventPublisher.publishEvent(new NoticeEvent(NoticeTaskParam.builder()
					.businessType(BusinessType.REPAIR.getCode())
					.triggerNode(TriggerNodeEnum.SIGN_IN.getCode())
					.triggerCondition(TriggerConditionEnum.CONDITION_3.getCode())
					.bizId(maintainSign.getPlanId())
					.tenantId(AuthUtil.getTenantId())
					.deliverTime(deliverTime)
					.build()
				));
			} else {
				JSONObject jsonObject = new JSONObject();
				jsonObject.put("planId", maintainSign.getPlanId());
				jsonObject.put("finishDate", maintainSign.getFinishDate());
				normalSend.sendPlanFinishDate(deliverTime, jsonObject.toJSONString());
			}
		}

		// 维修/配件 24小时不签退，系统自动签退
		if (MaintainPlanContentEnum.MAINTAIN_PARTS.getId() == typeStatus || MaintainPlanContentEnum.MAINTAIN_WX.getId() == typeStatus) {
			JSONObject jsonObject = new JSONObject();
			jsonObject.put("planId", maintainSign.getPlanId());
			jsonObject.put("typeStatus", typeStatus);
			jsonObject.put("maintainSignId", maintainSign.getId());
			long deliverTime = currentTimeMillis + 60000 * 60 * 24;
			alarmSend.sendWxPartsPlanSignOutDelayed(deliverTime, jsonObject.toJSONString());
		}

		// 插入任务记录
		PlanLogDTO planLogDTO = new PlanLogDTO();
		planLogDTO.setSignId(maintainSign.getId());
		planLogDTO.setAddress(maintainSign.getSignAddress());
		planLogDTO.setImage(maintainSign.getSignImage());
		planLogDTO.setSignStatus(maintainSign.getSignStatus());
		planLogDTO.setLongitude(maintainSign.getSignLongitude());
		planLogDTO.setLatitude(maintainSign.getSignLatitude());
		planLogDTO.setSignDate(new Date());
		List<MaintainSign> list = this.list(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getUserId, maintainSign.getUserId()).eq(MaintainSign::getPlanId, maintainSign.getPlanId()));
		if (list.size() == 1) {
			planLogDTO.setPlanArriveDate(planContentUser.getPlanArriveDate());
			MaintainPlanContentUser maintainPlanContentUser = maintainPlanContentUserService.getOne(Wrappers.<MaintainPlanContentUser>lambdaQuery().eq(MaintainPlanContentUser::getUserId, maintainSign.getUserId()).eq(MaintainPlanContentUser::getPlanId, maintainSign.getPlanId()));
			planLogDTO.setCreateTime(maintainPlanContentUser.getCreateTime());
		}
		if (maintainSign.getSignStatus().equals(2)) {
			planLogDTO.setExpDesc(WorkTrackStatusEnum.ADDRESS_ERROR.getTypeName());
		}
		malfunctionLogService.insertWorkLog(maintainSign.getPlanId(), WorkTrackStatusEnum.SIGN_IN.getTypeName(), planContent.getStatus(), JSONObject.toJSONString(planLogDTO), AuthUtil.getUserId(), user.getRealName());
		maintainPlanContentUserService.updatePlanUserSignInfo(maintainSign.getPlanId(), SignEnum.SIGN.getId(), AuthUtil.getUserId(), maintainSign.getSignStatus());

		//2023-2-10新增保存电梯的经纬度
		ElevatorDetail elevatorDetail = elevatorDetailService.getOne(Wrappers.<ElevatorDetail>lambdaQuery().eq(ElevatorDetail::getElevatorId, elevatorId));
		if (StrUtil.isEmpty(elevatorDetail.getLatitude()) && maintainSign.getSignStatus() == SignInStatusEnum.NORMAL.getId()) {
			elevatorDetail.setLatitude(maintainSign.getSignLatitude());
			elevatorDetail.setLongitude(maintainSign.getSignLongitude());
			elevatorDetailService.updateById(elevatorDetail);
		}
		Long planId = maintainSign.getPlanId();
		MaintainPlanContent currentPlan = maintainPlanContentService.getById(planId);
		Long eId = currentPlan.getElevatorId();
		Elevator currentElevator = elevatorService.getById(eId);

		// 发送电梯运行状态变更延时队列
		if (MaintainPlanContentEnum.MAINTAIN_WX.getId() == typeStatus) {
			int count = super.count(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, maintainSign.getPlanId()));
			// 第一次签到 当前电梯状态为停梯 签到提交电梯状态为正常
			if (count == 1 && currentElevator.getIsStop().equals(ElevatorStatusEnum.STOP.getStatus()) && maintainSign.getIsStop().equals(ElevatorStatusEnum.NORMAL.getStatus())) {

				// 停梯工单作业2/4小时未签退预警通知
//				JSONObject msg = new JSONObject();
//				msg.put("msgType", 2);
//				msg.put("contentType", 2);
//				msg.put("planId", planId);
//				msg.put("elevatorId", eId);
////				mqMessageService.sendElevatorStopMsg(DateUtil.date().getTime()+5*60*1000,JSONObject.toJSONString(msg));
//				mqMessageService.sendElevatorStopMsg(DateUtil.date().getTime() + 120 * 60 * 1000, JSONObject.toJSONString(msg));
//
//				// 停梯工单签到恢复正常运行预警通知
//				msg = new JSONObject();
//				msg.put("msgType", 3);
//				msg.put("planId", planId);
//				msg.put("elevatorId", eId);
//				mqMessageService.sendElevatorStopMsg(DateUtil.date().getTime(), JSONObject.toJSONString(msg));

				// 推送通知
				List<Integer> triggerConditions = new ArrayList<>();
				// 停梯工单作业2小时未签退预警通知
				triggerConditions.add(TriggerConditionEnum.CONDITION_10.getCode());
				// 停梯工单作业4小时未签退预警通知
				triggerConditions.add(TriggerConditionEnum.CONDITION_11.getCode());
				// 停梯工单签到恢复正常运行预警通知
				triggerConditions.add(TriggerConditionEnum.CONDITION_9.getCode());
				for (Integer triggerCondition : triggerConditions) {
					eventPublisher.publishEvent(new NoticeEvent(NoticeTaskParam.builder()
						.businessType(BusinessType.REPAIR.getCode())
						.triggerNode(TriggerNodeEnum.SIGN_IN.getCode())
						.triggerCondition(triggerCondition)
						.bizId(maintainSign.getPlanId())
						.tenantId(AuthUtil.getTenantId())
						.build()
					));
				}
			}
		}

		// 2023-9-04新增保存电梯停梯状态
		if (!Func.isNull(maintainSign.getIsStop())) {
			if (Func.isNull(eId)) {
				throw new ServiceException("工单不完整，请联系管理员，请关联电梯");
			}
			Integer isStop = maintainSign.getIsStop();
			if (!Func.isNull(isStop)) {
				elevatorService.update(Wrappers.<Elevator>lambdaUpdate()
					.set(Elevator::getIsStop, isStop)
					.set(Elevator::getUpdateTime, new Date())
					.set(Elevator::getUpdateUser, AuthUtil.getUserId())
					.eq(Elevator::getId, currentElevator.getId()));
			}
		}
		// 给飞书推送表格更新
		if ("592800".equals(AuthUtil.getTenantId())) {
			asyncHttpUtil.createPost(projectApiConfiguration.getWeb() + "/admin/lark/galaxy/elevator/repair/plan", Func.toJson(planContent), WebUtil.getRequest());
		}
		return Boolean.TRUE;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean signOut(MaintainSign maintainSign) {

		MaintainPlanContent planContent = planContentService.getById(maintainSign.getPlanId());
		if (!planContent.getStatus().equals(TaskStatusEnum.BY_PROCESSED.getStatus()) && planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_BY.getId())) {
			throw new ServiceException("任务状态已更新，请刷新页面");
		}
		if (!planContent.getStatus().equals(TaskStatusEnum.WX_UNDER_WAY.getStatus()) && planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_WX.getId())) {
			throw new ServiceException("任务状态已更新，请刷新页面");
		}
		if (!planContent.getStatus().equals(TaskStatusEnum.PARTS_CHANGE.getStatus()) && planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_PARTS.getId())) {
			throw new ServiceException("任务状态已更新，请刷新页面");
		}
		if (!planContent.getStatus().equals(TaskStatusEnum.SW_UNDER_WAY.getStatus()) && planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_AFFAIR.getId())) {
			throw new ServiceException("任务状态已更新，请刷新页面");
		}
		if (!planContent.getStatus().equals(TaskStatusEnum.ZJ_UNDER_WAY.getStatus()) && planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_CHECK.getId())) {
			throw new ServiceException("任务状态已更新，请刷新页面");
		}

		ElevatorDetailVO elevatorDetailVO = elevatorService.selectElevatorDetail(planContent.getElevatorId());
		List<MaintainPlanContentUser> planContentUsers = maintainPlanContentUserService.listUserByPlan(maintainSign.getPlanId());
		List<String> userName = planContentUsers.stream().map(MaintainPlanContentUser::getUserName).collect(Collectors.toList());

		if (MaintainPlanContentEnum.MAINTAIN_BY.getId() == planContent.getTypeStatus() || MaintainPlanContentEnum.MAINTAIN_WX.getId() == planContent.getTypeStatus()) {
			int count = super.count(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, maintainSign.getPlanId()).isNull(MaintainSign::getSignOutTime));
			if (count == 1 && maintainSign.getButtonType() == 0) {
				// 机器人消息内容
				RobotContentDTO robotContentDTO = new RobotContentDTO();
				robotContentDTO.setMaintainType(planContent.getTypeStatus());
				if (planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_BY.getId())) {
					robotContentDTO.setMaintainSubTypeDesc("【保养退场通知】");
					StringBuilder locationDesc = new StringBuilder();
					locationDesc.append(elevatorDetailVO.getBuildingName()).append("-").append(elevatorDetailVO.getElevatorAddress());
					robotContentDTO.setLocationDesc(locationDesc.toString());
				} else {
					MaintainMalfunctionWork malfunctionWork = malfunctionWorkService.list(Wrappers.<MaintainMalfunctionWork>lambdaQuery().eq(MaintainMalfunctionWork::getPlanId, planContent.getId()).orderByAsc(MaintainMalfunctionWork::getId)).get(0);
					robotContentDTO.setMaintainSubTypeDesc("【维修退场通知】");
					StringBuilder locationDesc = new StringBuilder();
					locationDesc.append(elevatorDetailVO.getBuildingName()).append("-").append(elevatorDetailVO.getElevatorAddress());
					robotContentDTO.setLocationDesc(locationDesc.toString());
					robotContentDTO.setMalfunctionDesc(malfunctionWork.getMfDesc());
				}
				robotContentDTO.setMaintainStatusDesc(TaskStatusEnum.getTaskName(planContent.getTypeStatus(), planContent.getStatus()));
				robotContentDTO.setElevatorStatusDesc(ElevatorStatusEnum.getName(maintainSign.getIsStop()));
				robotContentDTO.setMaintainPersonDesc(String.join(",", userName));
				robotContentDTO.setMaintainImgUrl(StringUtil.isNotBlank(maintainSign.getSignOutImage()) ? maintainSign.getSignOutImage() : "https://erised.oss-cn-shenzhen.aliyuncs.com/img/202308251732342.png");
				robotContentDTO.setMaintainTimeDesc(DateUtils.chineseDate(planContent.getFinishDate()));
				robotContentDTO.setNotPushCard(true);
				robotUtil.sendRobotMessage(RequestContextHolder.getRequestAttributes(), planContent.getElevatorId(), planContent.getId(), robotContentDTO);
			}
		}

		User user = userService.getById(maintainSign.getUserId());

		maintainSign.setSignOutTime(new Date());

		List<MaintainSign> signList = super.list(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getUserId, maintainSign.getUserId()).eq(MaintainSign::getPlanId, maintainSign.getPlanId()).isNull(MaintainSign::getSignOutTime).orderByDesc(MaintainSign::getId));
		if (Func.isEmpty(signList)) {
			throw new ServiceException("签退状态已变更，请刷新页面");
		}
		signList.forEach(sign -> {
			sign.setSignOutImage(maintainSign.getSignOutImage());
			sign.setSignOutTime(maintainSign.getSignOutTime());
			// 计算时间差
			Long timeInterval = DateUtil.between(sign.getSignTime(), maintainSign.getSignOutTime(), DateUnit.MINUTE);
			sign.setTimeInterval(timeInterval);
			sign.setSignOutAddress(maintainSign.getSignOutAddress());
			sign.setSignOutStatus(maintainSign.getSignOutStatus());
			sign.setSignOutLongitude(maintainSign.getSignOutLongitude());
			sign.setSignOutLatitude(maintainSign.getSignOutLatitude());
			sign.setSignOutDesc(maintainSign.getSignOutDesc());
		});
		// 插入任务记录
		PlanLogDTO planLogDTO = new PlanLogDTO();
		planLogDTO.setSignId(signList.get(0).getId());
		planLogDTO.setAddress(maintainSign.getSignOutAddress());
		planLogDTO.setImage(maintainSign.getSignOutImage());
		planLogDTO.setSignStatus(maintainSign.getSignOutStatus());
		planLogDTO.setLongitude(maintainSign.getSignOutLongitude());
		planLogDTO.setLatitude(maintainSign.getSignOutLatitude());
		if (maintainSign.getSignOutStatus().equals(2)) {
			planLogDTO.setExpDesc(WorkTrackStatusEnum.ADDRESS_ERROR.getTypeName());
		}
		malfunctionLogService.insertWorkLog(maintainSign.getPlanId(), WorkTrackStatusEnum.SIGN_OUT.getTypeName(), planContent.getStatus(), JSONObject.toJSONString(planLogDTO), AuthUtil.getUserId(), user.getRealName());
		maintainPlanContentUserService.updatePlanUserSignInfo(maintainSign.getPlanId(), SignEnum.SIGN_OUT.getId(), AuthUtil.getUserId(), maintainSign.getSignOutStatus());

		Long planId = maintainSign.getPlanId();
		MaintainPlanContent currentPlan = maintainPlanContentService.getById(planId);
		Long elevatorId = currentPlan.getElevatorId();
		Elevator currentElevator = elevatorService.getById(elevatorId);
		Integer oldIsStop = currentElevator.getIsStop();

		// 2023.09.01 迭代更新：新加入停梯状态变更
		if (!Func.isNull(maintainSign.getIsStop())) {
			if (Func.isNull(elevatorId)) {
				throw new ServiceException("工单不完整，请联系管理员，请关联电梯");
			}
			Integer isStop = maintainSign.getIsStop();
			if (!Func.isNull(isStop)) {
				currentElevator.setIsStop(isStop);
				elevatorService.updateById(currentElevator);
			}
		}
		this.updateBatchById(signList);

		// 发送电梯运行状态变更延时队列
		if (MaintainPlanContentEnum.MAINTAIN_WX.getId() == currentPlan.getTypeStatus()) {
			int count = super.count(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, maintainSign.getPlanId()).isNotNull(MaintainSign::getSignOutTime));
			// 第一次签退 当前电梯状态为停梯 签到提交电梯状态为正常
			if (count == 1 && currentElevator.getIsStop().equals(ElevatorStatusEnum.STOP.getStatus())) {
//				JSONObject msg = new JSONObject();
//				msg.put("msgType", 4);
//				msg.put("planId", planId);
//				msg.put("elevatorId", elevatorId);
//				msg.put("initStatusName", ElevatorStatusEnum.getName(currentElevator.getIsStop()));
//				msg.put("setStatusName", ElevatorStatusEnum.getName(maintainSign.getIsStop()));
//				mqMessageService.sendElevatorStopMsg(DateUtil.date().getTime(), JSONObject.toJSONString(msg));

				// 推送通知-停梯工单签退通知
				Map<String, String> extra = MapUtil.ofEntries(MapUtil.entry("initStatusName", ElevatorStatusEnum.getName(oldIsStop)), MapUtil.entry("setStatusName", ElevatorStatusEnum.getName(maintainSign.getIsStop())));
				eventPublisher.publishEvent(new NoticeEvent(NoticeTaskParam.builder()
					.businessType(BusinessType.REPAIR.getCode())
					.triggerNode(TriggerNodeEnum.SIGN_OUT.getCode())
					.triggerCondition(TriggerConditionEnum.CONDITION_12.getCode())
					.bizId(planContent.getId())
					.tenantId(AuthUtil.getTenantId())
					.extra(extra)
					.build()
				));
			}
		}
		// 给飞书推送表格更新，签退时暂时不用
//		if("592800".equals(AuthUtil.getTenantId())){
//			asyncHttpUtil.createPost(projectApiConfiguration.getWeb() + "/admin/lark/galaxy/elevator/repair/plan", Func.toJson(planContent), WebUtil.getRequest());
//		}
		return Boolean.TRUE;
	}

	/**
	 * 检查该维保任务所有
	 *
	 * @param elevatorPlanId
	 * @return
	 */
	private boolean checkPlanContents(Long elevatorPlanId) {
		// 统计该任务所有检查项
		int total = checkHistoryService.count(Wrappers.<MaintainCheckHistory>lambdaQuery().eq(MaintainCheckHistory::getPlanId, elevatorPlanId));
		// 统计该任务已完成的检查项
		int finished = checkHistoryService.count(Wrappers.<MaintainCheckHistory>lambdaQuery().eq(MaintainCheckHistory::getPlanId, elevatorPlanId).ne(MaintainCheckHistory::getStatus, 1));
		return total == finished;
	}

	/**
	 * 检查当前签退用户是否为最后一个签退
	 *
	 * @param maintainSign
	 * @return
	 */
	@Override
	public Boolean checkUserLastSign(MaintainSign maintainSign) {
		// 统计该任务签到人数
		int signCount = this.count(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, maintainSign.getPlanId()).eq(MaintainSign::getStatus, SignEnum.SIGN.getId()));
		// 统计该任务维保人员总数
//		int total = planContentUserService.count(Wrappers.<MaintainPlanContentUser>lambdaQuery().eq(MaintainPlanContentUser::getPlanId,maintainSign.getElevatorPlanId()));
		// 统计该任务已经签退的人数
		int signOutCount = this.count(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, maintainSign.getPlanId()).eq(MaintainSign::getStatus, SignEnum.SIGN_OUT.getId()));
		return (signCount - signOutCount) == 1;
	}

	/**
	 * 系统代签 任务提交时 未签退人员自动签退
	 *
	 * @param planId
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void checkUserSignOut(Long planId) {
		MaintainPlanContent planContent = planContentService.getById(planId);
		List<MaintainSign> signList = super.list(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, planId).isNull(MaintainSign::getSignOutTime));
		if (ObjectUtil.isNotEmpty(signList)) {
			signList.forEach(e -> {
				e.setSignOutStatus(SignOutStatusEnum.NORMAL.getId());
				e.setStatus(SignStatusEnum.SYSTEM.getId());
				e.setSignOutTime(new Date());
				e.setTimeInterval(0L);
				super.updateById(e);
				// 插入任务记录
				User user = userService.getById(e.getUserId());
				PlanLogDTO planLogDTO = new PlanLogDTO();
				planLogDTO.setSignId(e.getId());
				planLogDTO.setExpDesc(WorkTrackStatusEnum.SYSTEM_SIGN.getTypeName());
				if (planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_BY.getId())) {
					malfunctionLogService.insertWorkLog(e.getPlanId(), WorkTrackStatusEnum.SIGN_OUT.getTypeName(), TaskStatusEnum.BY_PROCESSED.getStatus(), JSONObject.toJSONString(planLogDTO), AuthUtil.getUserId(), user.getRealName());
				} else if (planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_WX.getId())) {
					malfunctionLogService.insertWorkLog(e.getPlanId(), WorkTrackStatusEnum.SIGN_OUT.getTypeName(), TaskStatusEnum.WX_UNDER_WAY.getStatus(), JSONObject.toJSONString(planLogDTO), AuthUtil.getUserId(), user.getRealName());
				} else if (planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_PARTS.getId())) {
					malfunctionLogService.insertWorkLog(e.getPlanId(), WorkTrackStatusEnum.SIGN_OUT.getTypeName(), TaskStatusEnum.PARTS_CHANGE.getStatus(), JSONObject.toJSONString(planLogDTO), AuthUtil.getUserId(), user.getRealName());
				} else if (planContent.getTypeStatus().equals(MaintainPlanContentEnum.MAINTAIN_AFFAIR.getId())) {
					malfunctionLogService.insertWorkLog(e.getPlanId(), WorkTrackStatusEnum.SIGN_OUT.getTypeName(), TaskStatusEnum.SW_UNDER_WAY.getStatus(), JSONObject.toJSONString(planLogDTO), AuthUtil.getUserId(), user.getRealName());
				}
				maintainPlanContentUserService.updatePlanUserSignInfo(e.getPlanId(), SignEnum.SIGN_OUT.getId(), e.getUserId(), e.getSignOutStatus());
			});
		}
	}

	/**
	 * 维修/配件工单24未签退，执行系统代签
	 *
	 * @param maintainSignId
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void wxPartsAutoSignOut(Long maintainSignId, Long planId, Integer typeStatus) {
		MaintainSign maintainSign = super.getById(maintainSignId);
		if (Func.isNotEmpty(maintainSign) && Func.isEmpty(maintainSign.getSignOutTime())) {
			maintainSign.setSignOutStatus(SignOutStatusEnum.NORMAL.getId());
			maintainSign.setStatus(SignStatusEnum.SYSTEM.getId());
			maintainSign.setSignOutTime(new Date());
			// 计算时间差
			Long timeInterval = DateUtil.between(maintainSign.getSignTime(), maintainSign.getSignOutTime(), DateUnit.MINUTE);
			maintainSign.setTimeInterval(timeInterval);
			super.updateById(maintainSign);
			// 插入任务记录
			PlanLogDTO planLogDTO = new PlanLogDTO();
			planLogDTO.setSignId(maintainSign.getId());
			planLogDTO.setExpDesc(WorkTrackStatusEnum.SYSTEM_SIGN.getTypeName());
			if (typeStatus.equals(MaintainPlanContentEnum.MAINTAIN_WX.getId())) {
				malfunctionLogService.insertWorkLog(planId, WorkTrackStatusEnum.SIGN_OUT.getTypeName(), TaskStatusEnum.WX_UNDER_WAY.getStatus(), JSONObject.toJSONString(planLogDTO), maintainSign.getTenantId());
			} else if (typeStatus.equals(MaintainPlanContentEnum.MAINTAIN_PARTS.getId())) {
				malfunctionLogService.insertWorkLog(planId, WorkTrackStatusEnum.SIGN_OUT.getTypeName(), TaskStatusEnum.PARTS_CHANGE.getStatus(), JSONObject.toJSONString(planLogDTO), maintainSign.getTenantId());
			}
			maintainPlanContentUserService.updatePlanUserSignInfo(planId, SignEnum.SIGN_OUT.getId(), maintainSign.getUserId(), maintainSign.getSignOutStatus());
		}
	}

	@Override
	public PlanUserSignCountDTO countUserSignError(Long planId, Long userId) {
		return baseMapper.countUserSignError(planId, userId);
	}

	@Override
	public List<MaintainSign> listByUserDate(PlanCheckStatisticsQueryDTO queryDTO, List<Long> userIds) {
		return baseMapper.listByUserDate(queryDTO, userIds);
	}

	@Override
	public List<MaintainSign> listCommitByUserDate(PlanCheckStatisticsQueryDTO queryDTO, List<Long> userIds) {
		return baseMapper.listCommitByUserDate(queryDTO, userIds);
	}

	@Override
	public ElevatorLastPlanVO selectUserLastSignImgByElevator(Long userId, Long elevatorId) {
		return baseMapper.selectUserLastSignImgByElevator(userId, elevatorId);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean offlineSign(MaintainSign sign) {

		log.info("================================= 离线同步开始 =================================");

		User user = userService.getById(sign.getUserId());
		MaintainPlanContent planContent = planContentService.getById(sign.getPlanId());
		Elevator elevator = elevatorService.getById(planContent.getElevatorId());
		long planDate = planContent.getPlanDate().getTime();
		long signDate = DateUtil.parse(DateUtil.format(sign.getSignTime(), "yyyy-MM-dd")).getTime();
		long nowDate = DateUtil.parse(DateUtil.format(DateUtil.date(), "yyyy-MM-dd")).getTime();
		long newPlanFinishTime = sign.getFinishDate().getTime();
		long oldPlanFinishTime = 0;
		if (ObjectUtil.isNotEmpty(planContent.getFinishDate())) {
			oldPlanFinishTime = planContent.getFinishDate().getTime();
		}
		// 当前工单 人员 签到时间表里已存在时 不做任何处理
		MaintainSign checkEntity = super.getOne(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getSignTime, sign.getSignTime()).eq(MaintainSign::getPlanId, sign.getPlanId()).eq(MaintainSign::getUserId, sign.getUserId()), Boolean.FALSE);
		if (ObjectUtil.isNotEmpty(checkEntity)) {
			log.info("================================= 存在相同签到时间 离线同步结束 =================================");
			return Boolean.TRUE;
		}

		// 签到日期大于当前时间不做任何处理 清除前端缓存
		if (sign.getSignTime().getTime() > DateUtil.date().getTime()) {
			log.info("================================= 签到时间大于当前时间 离线同步结束 SignTime : {} NowTime : {} =================================", sign.getSignTime(), DateUtil.date());
			return Boolean.TRUE;
		}
		// 签到日期小于计划时间不做任何处理 清除前端缓存
		if (signDate < planDate) {
			log.info("================================= 签到时间大于计划时间 离线同步结束 SignTime : {} NowTime : {} =================================", signDate, planDate);
			return Boolean.TRUE;
		}
		// 工单状态为维保签字或已完成则不做任何处理 清楚前端缓存
		if (planContent.getStatus().equals(TaskStatusEnum.BY_MAINTAIN_SIGN.getStatus()) || planContent.getStatus().equals(TaskStatusEnum.BY_SIGN.getStatus())) {
			log.info("================================= 工单状态已变更为维保完成或签字完成 离线同步结束 =================================");
			return Boolean.TRUE;
		}

		// 当工单状态为已提交时 确保人员未被清除与工单的关联关系
		if (planContent.getStatus().equals(TaskStatusEnum.BY_FINISH.getStatus())) {
			MaintainPlanContentUser lastPlanUser = maintainPlanContentUserService.getLastPlanUser(sign.getPlanId(), sign.getUserId());
			maintainPlanContentUserService.updateIsDeletedById(lastPlanUser.getId(), 0);
		}

		// 存在未签退记录时 直接系统代签
		MaintainSign oldSign = super.getOne(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getPlanId, sign.getPlanId()).eq(MaintainSign::getUserId, sign.getUserId()).isNull(MaintainSign::getSignOutTime));
		if (ObjectUtil.isNotEmpty(oldSign)) {
			oldSign.setStatus(SignStatusEnum.SYSTEM.getId());
			oldSign.setSignOutStatus(SignOutStatusEnum.NORMAL.getId());
			oldSign.setSignOutTime(sign.getSignTime());
			oldSign.setTimeInterval(0L);
			super.updateById(oldSign);
			maintainPlanContentUserService.updatePlanUserSignInfo(sign.getPlanId(), SignEnum.SIGN_OUT.getId(), sign.getUserId(), oldSign.getSignOutStatus());

			// 补充系统代签日志
			PlanLogDTO planLogDTO = new PlanLogDTO();
			planLogDTO.setSignId(oldSign.getId());
			planLogDTO.setExpDesc(WorkTrackStatusEnum.SYSTEM_SIGN.getTypeName());
			malfunctionLogService.insertWorkLog(oldSign.getPlanId(), WorkTrackStatusEnum.SIGN_OUT.getTypeName(), TaskStatusEnum.BY_PROCESSED.getStatus(), JSONObject.toJSONString(planLogDTO), AuthUtil.getUserId(), user.getRealName());
		}

		// 其他情况 先插入签到记录
		sign.setSignStatus(SignInStatusEnum.OFFLINE.getId());
		sign.setTenantId(AuthUtil.getTenantId());
		super.save(sign);
		maintainPlanContentUserService.updatePlanUserSignInfo(sign.getPlanId(), SignEnum.SIGN.getId(), sign.getUserId(), sign.getSignStatus());

		// 插入任务记录
		PlanLogDTO planLogDTO = new PlanLogDTO();
		planLogDTO.setSignId(sign.getId());
		planLogDTO.setImage(sign.getSignImage());
		planLogDTO.setSignStatus(sign.getSignStatus());
		planLogDTO.setExpDesc(WorkTrackStatusEnum.OFFLINE.getTypeName());
		malfunctionLogService.insertWorkLog(sign.getPlanId(), WorkTrackStatusEnum.SIGN_IN.getTypeName(), planContent.getStatus(), JSONObject.toJSONString(planLogDTO), AuthUtil.getUserId(), user.getRealName());

		long deliverTime = newPlanFinishTime - 5 * 60000;
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("planId", sign.getPlanId());
		jsonObject.put("finishDate", sign.getFinishDate());
		// 当前工单预计完成时间为空时 直接更新
		if (oldPlanFinishTime == 0) {
			planContent.setFinishDate(sign.getFinishDate());
			normalSend.sendPlanFinishDate(deliverTime, jsonObject.toJSONString());

			// 离线签到时间为当天时 同步更新电梯运行状态
			if (signDate == nowDate) {
				elevator.setIsStop(sign.getIsStop());
				elevatorService.updateById(elevator);

//				if(ObjectUtil.isNotEmpty(sign.getMessageDTO())){
//					robotUtil.offlineSignSendRobotMsgAsyn(sign.getMessageDTO(),planContent.getElevatorId());
//				}
			}
		} else {
			// 当前工单预计完成时间小于传入预计完成时间时更新
			if (newPlanFinishTime > oldPlanFinishTime) {
				planContent.setFinishDate(sign.getFinishDate());
				normalSend.sendPlanFinishDate(deliverTime, jsonObject.toJSONString());

				// 离线签到时间为当天时 同步更新电梯运行状态
				if (signDate == nowDate) {
					elevator.setIsStop(sign.getIsStop());
					elevatorService.updateById(elevator);

//					if(ObjectUtil.isNotEmpty(sign.getMessageDTO())){
//						robotUtil.offlineSignSendRobotMsgAsyn(sign.getMessageDTO(),planContent.getElevatorId());
//					}
				}
			}
		}

		// 工单当前状态为待开始 则变更状态为进行中
		if (planContent.getStatus().equals(TaskStatusEnum.BY_DISABLE.getStatus())) {
			planContent.setStatus(TaskStatusEnum.BY_PROCESSED.getStatus());

			// 生成工作项历史记录
			checkHistoryService.addHistory(sign.getPlanId());

			// 跟新任务扩展表任务开始时间
			MaintainPlanContentExt maintainPlanContentExt = maintainPlanContentExtService.getOne(Wrappers.<MaintainPlanContentExt>lambdaQuery().eq(MaintainPlanContentExt::getPlanId, sign.getPlanId()));
			if (ObjectUtil.isNotEmpty(maintainPlanContentExt.getPlanBeginTime())) {
				if (maintainPlanContentExt.getPlanBeginTime().getTime() > sign.getSignTime().getTime()) {
					maintainPlanContentExt.setPlanBeginTime(sign.getSignTime());
				}
			} else {
				maintainPlanContentExt.setPlanBeginTime(sign.getSignTime());
			}
			maintainPlanContentExtService.updateById(maintainPlanContentExt);

//			ElevatorDetailVO elevatorDetailVO = elevatorService.selectElevatorDetail(planContent.getElevatorId());
//			// 【保养开始】群消息推送
//			RobotContentDTO robotContentDTO = new RobotContentDTO();
//			robotContentDTO.setMaintainType(MaintainPlanContentEnum.MAINTAIN_BY.getId());
//			robotContentDTO.setMaintainSubTypeDesc("【开始保养通知】");
//			StringBuilder locationDesc = new StringBuilder();
//			locationDesc.append(elevatorDetailVO.getBuildingName()).append("-").append(elevatorDetailVO.getElevatorAddress());
//			robotContentDTO.setLocationDesc(locationDesc.toString());
//			robotContentDTO.setMaintainStatusDesc(TaskStatusEnum.getTaskName(MaintainPlanContentEnum.MAINTAIN_BY.getId(), planContent.getStatus()));
//			robotContentDTO.setElevatorStatusDesc(ElevatorStatusEnum.getName(sign.getIsStop()));
//			List<MaintainPlanContentUser> planUsers = maintainPlanContentUserService.listUserByPlan(planContent.getId());
//			robotContentDTO.setMaintainPersonDesc(planUsers.stream().map(t -> t.getUserName()).collect(Collectors.joining(",")));
//			robotContentDTO.setMaintainPersonImgDesc(planUsers.stream().map(t -> t.getAvatar()).collect(Collectors.joining(",")));
//			robotContentDTO.setMaintainImgUrl(sign.getSignImage());
//			robotContentDTO.setMaintainTimeDesc(DateUtils.chineseDate(sign.getFinishDate()));
//			robotUtil.sendRobotMessage(planContent.getElevatorId(), planContent.getId(), robotContentDTO);

		}
		// 签到日期大于计划日期并且不是今日 则直接代签签退
		if ((signDate > planDate && signDate != nowDate) || planContent.getStatus().equals(TaskStatusEnum.BY_FINISH.getStatus())) {
			MaintainSign signOut = new MaintainSign();
			signOut.setId(sign.getId());
			signOut.setStatus(SignStatusEnum.SYSTEM.getId());
			signOut.setSignOutStatus(SignOutStatusEnum.NORMAL.getId());
			signOut.setSignOutTime(sign.getSignTime());
			signOut.setTimeInterval(0L);
			super.updateById(signOut);
			maintainPlanContentUserService.updatePlanUserSignInfo(sign.getPlanId(), SignEnum.SIGN_OUT.getId(), sign.getUserId(), signOut.getSignOutStatus());

			// 补充系统代签日志
			planLogDTO = new PlanLogDTO();
			planLogDTO.setSignId(signOut.getId());
			planLogDTO.setExpDesc(WorkTrackStatusEnum.SYSTEM_SIGN.getTypeName());
			malfunctionLogService.insertWorkLog(sign.getPlanId(), WorkTrackStatusEnum.SIGN_OUT.getTypeName(), TaskStatusEnum.BY_PROCESSED.getStatus(), JSONObject.toJSONString(planLogDTO), AuthUtil.getUserId(), user.getRealName());

		}

		planContentService.updateById(planContent);

		log.info("================================= 离线签到完整结束 =================================");
		return Boolean.TRUE;
	}


	@Override
	public List<PlanSignVO> listPlanSign(Long planId) {
		return baseMapper.listPlanSign(planId);
	}

	@Override
	public HashMap<String, Object> signPlanCheck(Long userId, Long planId) {
//        HashMap<String, Object> resultMap = new HashMap<>(3);
//        List<MaintainPlanContent> planContents = planContentService.getPlanByUserInBegin(userId, planId);
//        if (ObjectUtil.isEmpty(planContents)) {
//            resultMap.put("result", Boolean.TRUE);
//        } else {
//            for (MaintainPlanContent plan : planContents) {
//                int count = this.count(Wrappers.<MaintainSign>lambdaQuery().eq(MaintainSign::getElevatorPlanId, plan.getId()).eq(MaintainSign::getUserId, userId));
//                if (count == 1) {
//                    resultMap.put("result", Boolean.FALSE);
//                    resultMap.put("planId", plan.getId());
//                    resultMap.put("elevatorId", plan.getElevatorId());
//                    break;
//                } else {
//                    resultMap.put("result", Boolean.TRUE);
//                }
//            }
//        }
//        return resultMap;
		return null;
	}

	@Override
	public PlanSignCheckVO planSignOutCheck(Long planId) {
		// 0. 条件校验，参数准备
		if (Func.isNull(planId) || Func.isNull(maintainPlanContentService.getById(planId))) {
			throw new ServiceException("业务异常，参数错误！");
		}
		Long currentUser = AuthUtil.getUserId();
		PlanSignCheckVO planSignCheckVO = new PlanSignCheckVO();
		planSignCheckVO.setIsExist(Boolean.FALSE);

		// 1. 获取当前工单的类型, 查询当前用户当前工单作业列表，根据作业列表遍历签到表，根据工单分组，获取签到最近1条数据
		MaintainPlanContent currentPlan = maintainPlanContentService.getById(planId);
		Integer typeStatus = currentPlan.getTypeStatus();
		List<MaintainSign> maintainSigns = baseMapper.selectSignListByTypeStatus(currentUser, typeStatus);
		// 2. 遍历当前签到列表，若签退状态为空或者签退时间为空，则判定为未签退
		if (Func.isNotEmpty(maintainSigns)) {
			List<MaintainSign> filtered = maintainSigns.stream()
				.filter(f -> Func.isNull(f.getSignOutTime()) || Func.isNull(f.getSignOutStatus()))
				.collect(Collectors.toList());
			// 3. 若由步骤 2 获取的未签退签到列表不为空或长度不为0，获取第1条，并补充完整信息
			if (Func.isNotEmpty(filtered)) {
				MaintainSign maintainSign = filtered.get(0);
				Long notSignOutPlanId = maintainSign.getPlanId();
				PlanSignCheckVO result = baseMapper.getNoSignOutMessage(notSignOutPlanId);
				result.setIsExist(Boolean.TRUE);
				return result;
			}
		}
		return planSignCheckVO;
	}

	@Override
	public List<MaintainSign> listByPlanUserNotSignOut(Long planId, Long userId) {
		return baseMapper.listByPlanUserNotSignOut(planId, userId);
	}


}





